/**
2	 * Copyright (C) 2011 JogAmp Community. All rights reserved.
3	 *
4	 * Permission is hereby granted, free of charge, to any person obtaining a
5	 * copy of this software and associated documentation files (the "Software"),
6	 * to deal in the Software without restriction, including without limitation
7	 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8	 * and/or sell copies of the Software, and to permit persons to whom the
9	 * Software is furnished to do so, subject to the following conditions:
10	 *
11	 * The above copyright notice and this permission notice shall be included
12	 * in all copies or substantial portions of the Software.
13	 *
14	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15	 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17	 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18	 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19	 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20	 */
21	package com.jogamp.opengl.test.junit.jogl.demos;
22	
23	import java.nio.FloatBuffer;
24	
25	import javax.media.opengl.GL;
26	
27	import com.jogamp.common.nio.Buffers;
28	import com.jogamp.opengl.util.GLArrayDataServer;
29	
30	/**
31	 * GearsObject.java <BR>
32	 * @author Brian Paul (converted to Java by Ron Cemer and Sven Gothel) <P>
33	 */
34	public abstract class GearsObject {
35	    public static final FloatBuffer red = Buffers.newDirectFloatBuffer( new float[] { 0.8f, 0.1f, 0.0f, 0.7f } );
36	    public static final FloatBuffer green = Buffers.newDirectFloatBuffer( new float[] { 0.0f, 0.8f, 0.2f, 0.7f } );
37	    public static final FloatBuffer blue = Buffers.newDirectFloatBuffer( new float[] { 0.2f, 0.2f, 1.0f, 0.7f } );
38	    public static final float M_PI = (float)Math.PI;
39	   
40	    public GLArrayDataServer frontFace;
41	    public GLArrayDataServer frontSide;
42	    public GLArrayDataServer backFace;
43	    public GLArrayDataServer backSide;
44	    public GLArrayDataServer outwardFace;
45	    public GLArrayDataServer insideRadiusCyl;
46	    public boolean isShared;
47	
48	    public abstract GLArrayDataServer createInterleaved(int comps, int dataType, boolean normalized, int initialSize, int vboUsage);
49	    public abstract void addInterleavedVertexAndNormalArrays(GLArrayDataServer array, int components);
50	    public abstract void draw(GL gl, float x, float y, float angle, FloatBuffer color);
51	   
52	    public void destroy(GL gl) {
53	        if(!isShared) {
54	            // could be already destroyed by shared configuration
55	            if(null != frontFace) {
56	                frontFace.destroy(gl);
57	            }
58	            if(null != frontSide) {
59	                frontSide.destroy(gl);
60	            }
61	            if(null != backFace) {
62	                backFace.destroy(gl);
63	            }
64	            if(null != backSide) {
65	                backSide.destroy(gl);
66	            }
67	            if(null != outwardFace) {
68	                outwardFace.destroy(gl);
69	            }
70	            if(null != insideRadiusCyl) {
71	                insideRadiusCyl.destroy(gl);
72	            }
73	        }
74	        frontFace=null;
75	        frontSide=null;
76	        backFace=null;
77	        backSide=null;
78	        outwardFace=null;
79	        insideRadiusCyl=null;           
80	        isShared = false;
81	    }
82	   
83	    public GearsObject ( GearsObject shared ) {
84	        isShared = true;
85	        frontFace = shared.frontFace;
86	        frontSide = shared.frontSide;
87	        backFace = shared.backFace;
88	        backSide = shared.backSide;
89	        outwardFace = shared.outwardFace;
90	        insideRadiusCyl = shared.insideRadiusCyl;
91	    }
92	           
93	    public GearsObject (
94	            float inner_radius,
95	            float outer_radius,
96	            float width,
97	            int teeth,
98	            float tooth_depth)
99	    {
100	        final float dz = width * 0.5f;
101	        int i;
102	        float r0, r1, r2;
103	        float angle, da;
104	        float u, v, len;
105	        float s[] = new float[5];
106	        float c[] = new float[5];
107	        float normal[] = new float[3];
108	        // final int tris_per_tooth = 32;
109	
110	        isShared = false;
111	       
112	        r0 = inner_radius;
113	        r1 = outer_radius - tooth_depth / 2.0f;
114	        r2 = outer_radius + tooth_depth / 2.0f;
115	
116	        da = 2.0f * (float) Math.PI / teeth / 4.0f;
117	
118	        s[4] = 0; // sin(0f)
119	        c[4] = 1; // cos(0f)
120	
121	        frontFace = createInterleaved(6, GL.GL_FLOAT, false, 4*teeth+2, GL.GL_STATIC_DRAW);
122	        addInterleavedVertexAndNormalArrays(frontFace, 3);
123	        backFace = createInterleaved(6, GL.GL_FLOAT, false, 4*teeth+2, GL.GL_STATIC_DRAW);
124	        addInterleavedVertexAndNormalArrays(backFace, 3);
125	        frontSide = createInterleaved(6, GL.GL_FLOAT, false, 6*teeth, GL.GL_STATIC_DRAW);
126	        addInterleavedVertexAndNormalArrays(frontSide, 3);
127	        backSide = createInterleaved(6, GL.GL_FLOAT, false, 6*teeth, GL.GL_STATIC_DRAW);
128	        addInterleavedVertexAndNormalArrays(backSide, 3);
129	        outwardFace = createInterleaved(6, GL.GL_FLOAT, false, 4*4*teeth+2, GL.GL_STATIC_DRAW);
130	        addInterleavedVertexAndNormalArrays(outwardFace, 3);
131	        insideRadiusCyl = createInterleaved(6, GL.GL_FLOAT, false, 2*teeth+2, GL.GL_STATIC_DRAW);
132	        addInterleavedVertexAndNormalArrays(insideRadiusCyl, 3);
133	
134	        for (i = 0; i < teeth; i++) {
135	            angle = i * 2.0f * M_PI / teeth;
136	            sincos(angle + da * 0f, s, 0, c, 0);
137	            sincos(angle + da * 1f, s, 1, c, 1);
138	            sincos(angle + da * 2f, s, 2, c, 2);
139	            sincos(angle + da * 3f, s, 3, c, 3);
140	           
141	            /* front  */
142	            normal[0] = 0.0f;
143	            normal[1] = 0.0f;
144	            normal[2] = 1.0f;
145	           
146	            /* front face - GL.GL_TRIANGLE_STRIP */
147	            vert(frontFace, r0 * c[0], r0 * s[0], dz, normal);
148	            vert(frontFace, r1 * c[0], r1 * s[0], dz, normal);
149	            vert(frontFace, r0 * c[0], r0 * s[0], dz, normal);
150	            vert(frontFace, r1 * c[3], r1 * s[3], dz, normal);
151	           
152	            /* front sides of teeth - GL.GL_TRIANGLES */
153	            vert(frontSide, r1 * c[0], r1 * s[0], dz, normal);
154	            vert(frontSide, r2 * c[1], r2 * s[1], dz, normal);       
155	            vert(frontSide, r2 * c[2], r2 * s[2], dz, normal);
156	            vert(frontSide, r1 * c[0], r1 * s[0], dz, normal);
157	            vert(frontSide, r2 * c[2], r2 * s[2], dz, normal);       
158	            vert(frontSide, r1 * c[3], r1 * s[3], dz, normal);
159	           
160	            /* back */
161	            normal[0] = 0.0f;
162	            normal[1] = 0.0f;
163	            normal[2] = -1.0f;
164	           
165	            /* back face - GL.GL_TRIANGLE_STRIP */
166	            vert(backFace, r1 * c[0], r1 * s[0], -dz, normal);
167	            vert(backFace, r0 * c[0], r0 * s[0], -dz, normal);
168	            vert(backFace, r1 * c[3], r1 * s[3], -dz, normal);
169	            vert(backFace, r0 * c[0], r0 * s[0], -dz, normal);
170	           
171	            /* back sides of teeth - GL.GL_TRIANGLES*/
172	            vert(backSide, r1 * c[3], r1 * s[3], -dz, normal);
173	            vert(backSide, r2 * c[2], r2 * s[2], -dz, normal);
174	            vert(backSide, r2 * c[1], r2 * s[1], -dz, normal);
175	            vert(backSide, r1 * c[3], r1 * s[3], -dz, normal);
176	            vert(backSide, r2 * c[1], r2 * s[1], -dz, normal);       
177	            vert(backSide, r1 * c[0], r1 * s[0], -dz, normal);
178	           
179	            /* outward faces of teeth */
180	            u = r2 * c[1] - r1 * c[0];
181	            v = r2 * s[1] - r1 * s[0];
182	            len = (float)Math.sqrt(u * u + v * v);
183	            u /= len;
184	            v /= len;
185	            normal[0] =    v;
186	            normal[1] =   -u;
187	            normal[2] = 0.0f;
188	
189	            vert(outwardFace, r1 * c[0], r1 * s[0],  dz, normal);
190	            vert(outwardFace, r1 * c[0], r1 * s[0], -dz, normal);
191	            vert(outwardFace, r2 * c[1], r2 * s[1],  dz, normal);
192	            vert(outwardFace, r2 * c[1], r2 * s[1], -dz, normal);
193	
194	            normal[0] = c[0];
195	            normal[1] = s[0];
196	            vert(outwardFace, r2 * c[1], r2 * s[1],  dz, normal);
197	            vert(outwardFace, r2 * c[1], r2 * s[1], -dz, normal);
198	            vert(outwardFace, r2 * c[2], r2 * s[2],  dz, normal);
199	            vert(outwardFace, r2 * c[2], r2 * s[2], -dz, normal);
200	
201	            normal[0] = ( r1 * s[3] - r2 * s[2] );
202	            normal[1] = ( r1 * c[3] - r2 * c[2] ) * -1.0f ;
203	            vert(outwardFace, r2 * c[2], r2 * s[2],  dz, normal);
204	            vert(outwardFace, r2 * c[2], r2 * s[2], -dz, normal);       
205	            vert(outwardFace, r1 * c[3], r1 * s[3],  dz, normal);
206	            vert(outwardFace, r1 * c[3], r1 * s[3], -dz, normal);
207	
208	            normal[0] = c[0];
209	            normal[1] = s[0];
210	            vert(outwardFace, r1 * c[3], r1 * s[3],  dz, normal);
211	            vert(outwardFace, r1 * c[3], r1 * s[3], -dz, normal);
212	            vert(outwardFace, r1 * c[0], r1 * s[0],  dz, normal);
213	            vert(outwardFace, r1 * c[0], r1 * s[0], -dz, normal);
214	           
215	            /* inside radius cylinder */
216	            normal[0] = c[0] * -1.0f;
217	            normal[1] = s[0] * -1.0f;
218	            normal[2] = 0.0f;
219	            vert(insideRadiusCyl, r0 * c[0], r0 * s[0], -dz, normal);
220	            vert(insideRadiusCyl, r0 * c[0], r0 * s[0],  dz, normal);
221	        }
222	        /* finish front face */
223	        normal[0] = 0.0f;
224	        normal[1] = 0.0f;
225	        normal[2] = 1.0f;
226	        vert(frontFace, r0 * c[4], r0 * s[4], dz, normal);
227	        vert(frontFace, r1 * c[4], r1 * s[4], dz, normal);
228	        frontFace.seal(true);
229	       
230	        /* finish back face */
231	        normal[2] = -1.0f;             
232	        vert(backFace, r1 * c[4], r1 * s[4], -dz, normal);
233	        vert(backFace, r0 * c[4], r0 * s[4], -dz, normal);
234	        backFace.seal(true);
235	       
236	        backSide.seal(true);
237	        frontSide.seal(true);
238	       
239	        /* finish outward face */
240	        sincos(da * 1f, s, 1, c, 1);
241	        u = r2 * c[1] - r1 * c[4];
242	        v = r2 * s[1] - r1 * s[4];
243	        len = (float)Math.sqrt(u * u + v * v);
244	        u /= len;
245	        v /= len;
246	        normal[0] =    v;
247	        normal[1] =   -u;
248	        normal[2] = 0.0f;
249	        vert(outwardFace, r1 * c[4], r1 * s[4],  dz, normal);
250	        vert(outwardFace, r1 * c[4], r1 * s[4], -dz, normal);       
251	        outwardFace.seal(true);
252	
253	        /* finish inside radius cylinder */
254	        normal[0] = c[4] * -1.0f;
255	        normal[1] = s[4] * -1.0f;
256	        normal[2] = 0.0f;
257	        vert(insideRadiusCyl, r0 * c[4], r0 * s[4], -dz, normal);
258	        vert(insideRadiusCyl, r0 * c[4], r0 * s[4],  dz, normal);
259	        insideRadiusCyl.seal(true);
260	    }
261	
262	    static void vert(GLArrayDataServer array, float x, float y, float z, float n[]) {
263	        array.putf(x);
264	        array.putf(y);
265	        array.putf(z);
266	        array.putf(n[0]);
267	        array.putf(n[1]);
268	        array.putf(n[2]);
269	    }
270	   
271	    static void sincos(float x, float sin[], int sinIdx, float cos[], int cosIdx) {
272	        sin[sinIdx] = (float) Math.sin(x);
273	        cos[cosIdx] = (float) Math.cos(x);
274	    }
275	}